
# 从 collections 模块导入 defaultdict，用于创建默认值的字典
from collections import defaultdict
# 导入 inspect 模块，用于获取对象的信息
import inspect
# 导入 json 模块，用于处理 JSON 数据
import json
# 导入 os 模块，用于与操作系统进行交互，处理文件路径等
import os

# 从 enum 模块导入 IntEnum，用于创建整数枚举类型
from enum import IntEnum

# 从 qtpy 导入 QtGui、QtWidgets 和 QtCore 模块，提供图形用户界面相关功能
from qtpy import QtGui, QtWidgets, QtCore

# 从 src 核心的通用模块导入单例装饰器
from src.Core.Common import SingletonDecorator
# 从 src 配置管理模块导入配置管理器
from src.ConfigManager import ConfigManager

# 获取当前文件所在的目录
FILE_DIR = os.path.dirname(__file__)
# 定义样式文件的路径
STYLE_PATH = os.path.join(FILE_DIR, "style.css")
# 定义主题文件所在的目录路径
THEMES_PATH = os.path.join(os.path.dirname(FILE_DIR), "Themes")


class ConnectionTypes(IntEnum):
    """
    定义连接类型的枚举类，用于表示不同的连接样式。
    """
    Cubic = 0
    Circuit = 1
    ComplexCircuit = 2
    Linear = 3


class Colors:
    """
    定义一些常用颜色的类，使用 QtGui.QColor 表示。
    """
    # 纯黑色
    AbsoluteBlack = QtGui.QColor(0, 0, 0, 255)
    # 深灰色
    DarkGray = QtGui.QColor(60, 60, 60)
    # 脏笔颜色，半透明白色
    DirtyPen = QtGui.QColor(250, 250, 250, 200)
    # 灰色
    Gray = QtGui.QColor(110, 110, 110)
    # 绿色
    Green = QtGui.QColor(96, 169, 23, 255)
    # 节点背景颜色，半透明深灰色
    NodeBackgrounds = QtGui.QColor(40, 40, 40, 200)
    # 节点名称矩形的蓝色
    NodeNameRectBlue = QtGui.QColor(28, 74, 149, 200)
    # 节点名称矩形的绿色
    NodeNameRectGreen = QtGui.QColor(74, 124, 39, 200)
    # 节点选中时的画笔颜色，半透明浅灰色
    NodeSelectedPenColor = QtGui.QColor(200, 200, 200, 150)
    # 红色
    Red = QtGui.QColor(255, 0, 0, 255)
    # 白色，半透明
    White = QtGui.QColor(255, 255, 255, 200)
    # 黄色
    Yellow = QtGui.QColor(255, 211, 25)
    # 橙色
    Orange = QtGui.QColor(209, 84, 0)


@SingletonDecorator
class editableStyleSheet:
    """
    可编辑的样式表单例类，用于管理应用程序的样式和主题。
    可以序列化和加载样式预设，更新应用程序的样式表。
    """
    def __init__(self, appInstance=None):
        """
        初始化可编辑样式表类。

        :param appInstance: 应用程序实例，默认为 None
        """
        # 保存应用程序实例
        self.appInstance = appInstance

        # 定义文本颜色
        self.TextColor = QtGui.QColor(228, 228, 228)
        # 定义主颜色
        self.MainColor = QtGui.QColor(215, 128, 26)
        # 定义背景颜色
        self.BgColor = QtGui.QColor(53, 53, 53)
        # 定义更深的背景颜色
        self.BgColorDarker = QtGui.QColor(50, 50, 50)
        # 定义更亮的背景颜色
        self.BgColorBright = QtGui.QColor(82, 82, 82)
        # 定义边框颜色
        self.BorderColor = QtGui.QColor(10, 10, 10)
        # 定义日志区域的背景颜色
        self.LoggerBgColor = QtGui.QColor(35, 35, 35)
        # 定义输入框的颜色
        self.InputFieldColor = QtGui.QColor(32, 32, 32)
        # 定义文本选中时的颜色
        self.TextSelectedColor = QtGui.QColor(255, 255, 255)
        # 定义按钮的颜色
        self.ButtonsColor = QtGui.QColor(60, 60, 60)
        # 定义画布的背景颜色
        self.CanvasBgColor = QtGui.QColor(35, 35, 35)
        # 定义画布网格的颜色，半透明
        self.CanvasGridColor = QtGui.QColor(20, 20, 20, 100)
        # 定义更深的画布网格颜色
        self.CanvasGridColorDarker = QtGui.QColor(20, 20, 20)
        # 定义是否绘制网格，列表形式方便存储配置
        self.DrawGrid = [1]
        # 定义精细网格的大小
        self.GridSizeFine = [10]
        # 定义大网格的大小
        self.GridSizeHuge = [100]
        # 定义是否绘制网格编号
        self.DrawNumbers = [0]
        # 定义是否设置应用程序的样式表
        self.SetAppStyleSheet = [1]
        # 定义细节层次的编号
        self.LOD_Number = [4]
        # 定义节点的开关状态
        self.NodeSwitch = [3]
        # 定义连接的开关状态
        self.ConnectionSwitch = [3]
        # 定义引脚的开关状态
        self.PinSwitch = [3]
        # 定义画布的开关状态
        self.CanvasSwitch = [3]
        # 定义连接模式，使用 ConnectionTypes 枚举
        self.ConnectionMode = [ConnectionTypes.Circuit]
        # 定义连接的圆角半径
        self.ConnectionRoundness = [5]
        # 定义连接的偏移量
        self.ConnectionOffset = [20]

        # 存储默认颜色值
        self.storeDefaults()
        # 初始化预设主题字典
        self.presets = {}
        # 加载主题预设
        self.loadPresets(THEMES_PATH)
        try:
            # 从配置文件中获取主题名称
            themeName = ConfigManager().getPrefsValue("PREFS", "Theme/Theme_Name")
            if themeName:
                # 如果有主题名称，加载对应的主题数据
                self.loadFromData(self.presets[themeName])
            else:
                if len(self.presets) > 0:
                    # 如果没有主题名称且有预设主题，加载第一个主题数据
                    self.loadFromData(self.presets[list(self.presets.keys())[0]])
        except:
            pass

    def storeDefaults(self):
        """
        存储所有 QtGui.QColor 类型属性的默认值。
        """
        for name, obj in inspect.getmembers(self):
            if isinstance(obj, QtGui.QColor):
                # 为每个 QtGui.QColor 对象添加 default 属性，存储其初始 RGB 值
                obj.default = obj.getRgb()

    def serialize(self):
        """
        将样式表的颜色和列表属性序列化为 JSON 格式的数据。

        :return: 包含样式表数据的字典
        """
        result = defaultdict(list)
        for name, obj in inspect.getmembers(self):
            if isinstance(obj, QtGui.QColor):
                # 将 QtGui.QColor 对象的 RGB 值添加到结果字典中
                result[name].append(obj.getRgb())
            elif isinstance(obj, list):
                # 将列表属性添加到结果字典中
                result[name].append(obj)

        return {"PyFLowStyleSheet": result}

    def loadPresets(self, folder):
        """
        从指定文件夹中加载主题预设。

        :param folder: 主题预设所在的文件夹路径
        """
        self.presets = {}
        for file in os.listdir(folder):
            # 获取文件名和扩展名
            name, _type = os.path.splitext(file)
            if _type == ".json":
                try:
                    # 打开 JSON 文件并加载数据
                    with open(os.path.join(folder, file), "r") as f:
                        data = json.load(f)
                        self.presets[name] = data
                except:
                    pass

    def loadFromData(self, data):
        """
        从数据中加载样式表配置，并更新应用程序的样式。

        :param data: 包含样式表配置的字典
        """
        if list(data.keys())[0] == "PyFLowStyleSheet":
            data = data["PyFLowStyleSheet"]
            for name in data.keys():
                if isinstance(data[name], list):
                    # 设置颜色或列表属性的值
                    self.setColor(name, data[name][0])
            # 更新应用程序的样式
            self.updateApp()

    def setColor(self, name, color, update=False):
        """
        设置指定名称的颜色或列表属性的值。

        :param name: 属性名称
        :param color: 颜色值或列表值
        :param update: 是否更新应用程序的样式，默认为 False
        """
        value = color
        if not isinstance(color, QtGui.QColor):
            if isinstance(color, list) and len(color) >= 3:
                a = 255
                if len(color) == 4:
                    a = color[3]
                # 将列表转换为 QtGui.QColor 对象
                color = QtGui.QColor(color[0], color[1], color[2], a)
        for objname, obj in inspect.getmembers(self):
            if objname == name:
                if isinstance(obj, QtGui.QColor):
                    # 设置 QtGui.QColor 对象的 RGBA 值
                    obj.setRgba(color.rgba())
                elif isinstance(obj, list):
                    if isinstance(value, list):
                        value = value[0]
                    # 设置列表属性的值
                    obj[0] = value
                if update:
                    # 如果需要更新，调用 updateApp 方法更新应用程序的样式
                    self.updateApp()

    def updateApp(self):
        """
        调用应用程序中所有部件的 update 方法，并设置应用程序的样式表。
        """
        topWindow = self.appInstance

        if self.appInstance and self.appInstance.currentSoftware == "standalone":
            # 如果是独立运行的应用程序，获取当前的 QApplication 实例
            topWindow = QtWidgets.QApplication.instance()

        if self.SetAppStyleSheet[0] > 0:
            if topWindow:
                # 设置应用程序的样式表
                topWindow.setStyleSheet(self.getStyleSheet())
                for widget in topWindow.allWidgets():
                    if isinstance(widget, QtWidgets.QListView):
                        # 更新 QListView 的视口
                        widget.viewport().update()
                    elif isinstance(widget, QtWidgets.QHeaderView):
                        # 更新 QHeaderView 的视口
                        widget.viewport().update()
                    else:
                        # 更新其他部件
                        widget.update()

    def getStyleSheet(self):
        """
        从样式文件中读取样式字符串，并替换其中的颜色占位符。

        :return: 替换颜色占位符后的样式字符串
        """
        # 创建一个更浅的主颜色，透明度为 128
        MainColor_Lighter = QtGui.QColor(self.MainColor)
        MainColor_Lighter.setAlpha(128)
        # 创建按钮渐变的起始颜色
        ButtonG1 = self.ButtonsColor.lighter(120)
        # 创建按钮渐变的结束颜色
        ButtonG3 = self.ButtonsColor.darker(110)
        # 创建输入框悬停时的颜色
        InputFieldHover = self.InputFieldColor.lighter(200)
        with open(STYLE_PATH, "r") as f:
            styleString = f.read()
            return styleString % (
                "rgba%s" % str(self.TextColor.getRgb()),
                "rgba%s" % str(self.BgColor.getRgb()),
                "rgba%s" % str(self.BgColorDarker.getRgb()),
                "rgba%s" % str(self.BgColorBright.getRgb()),
                "rgba%s" % str(self.MainColor.getRgb()),
                "rgba%s" % str(MainColor_Lighter.getRgb()),
                "rgba%s" % str(MainColor_Lighter.getRgb()),
                "rgba%s" % str(self.BorderColor.getRgb()),
                "rgba%s" % str(self.InputFieldColor.getRgb()),
                "rgba%s" % str(InputFieldHover.getRgb()),
                "rgba%s" % str(MainColor_Lighter.getRgb()),
                "rgba%s" % str(self.TextSelectedColor.getRgb()),
                "rgba%s" % str(ButtonG1.getRgb()),
                "rgba%s" % str(self.ButtonsColor.getRgb()),
                "rgba%s" % str(ButtonG3.getRgb()),
                "rgba%s" % str(QtGui.QColor(0, 0, 0, 100).getRgb()),
            )

    def getSliderStyleSheet(self, name):
        """
        根据名称获取滑块的样式表。

        :param name: 滑块样式表的名称
        :return: 对应的滑块样式表字符串
        """
        Styles = {
            "sliderStyleSheetA": """
        QWidget{
            border: 1.25 solid black;
        }
        QSlider::groove:horizontal,
            QSlider::sub-page:horizontal {
            background: %s;
        }
        QSlider::add-page:horizontal,
            QSlider::sub-page:horizontal:disabled {
            background: rgb(32, 32, 32);
        }
        QSlider::add-page:horizontal:disabled {
            background: grey;
        }
        QSlider::handle:horizontal {
            width: 1px;
         }
        """
            % "rgba%s"
            % str(self.MainColor.getRgb()),
            "sliderStyleSheetB": """
        QSlider::groove:horizontal {
            border: 1px solid #bbb;
            background: white;
            height: 3px;
            border-radius: 2px;
        }
        QSlider::sub-page:horizontal {
            background: %s;
            border: 0px solid #777;
            height: 3px;
            border-radius: 2px;
        }
        QSlider::add-page:horizontal {
            background: #fff;
            border: 1px solid #777;
            height: 3px;
            border-radius: 2px;
        }
        QSlider::handle:horizontal {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #eee, stop:1 #ccc);
            border: 1px solid #777;
            width: 4px;
            margin-top: -8px;
            margin-bottom: -8px;
            border-radius: 2px;
            height : 10px;
        }
        QSlider::handle:horizontal:hover {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #fff, stop:1 #ddd);
            border: 1px solid #444;
            border-radius: 2px;
        }
        QSlider::sub-page:horizontal:disabled {
            background: #bbb;
            border-color: #999;
        }

        QSlider::add-page:horizontal:disabled {
            background: #eee;
            border-color: #999;
        }
        QSlider::handle:horizontal:disabled {
            background: #eee;
            border: 1px solid #aaa;
            border-radius: 2px;
            height : 10;
        }
        """
            % "rgba%s"
            % str(self.MainColor.getRgb()),
            "sliderStyleSheetC": """
        QSlider,QSlider:disabled,QSlider:focus{
                                  background: qcolor(0,0,0,0);   }

         QSlider::groove:horizontal {
            border: 1px solid #999999;
            background: qcolor(0,0,0,0);
         }
        QSlider::handle:horizontal {
            background:  rgba(255, 255, 255, 150);
            width: 10px;
            border-radius: 4px;
            border: 1.5px solid black;
         }
         QSlider::handle:horizontal:hover {
            border: 2.25px solid %s;
         }
        """
            % "rgba%s"
            % str(self.MainColor.getRgb()),
            "draggerstyleSheet": """
        QGroupBox{
            border: 0.5 solid darkgrey;
            background : black;
            color: white;
        }
        QLabel{
            background: transparent;
            border: 0 solid transparent;
            color: white;
        }
        """,
            "draggerstyleSheetHover": """
        QGroupBox{
            border: 0.5 solid darkgrey;
            background : %s;
            color: white;
        }
        QLabel{
            background: transparent;
            border: 0 solid transparent;
            color: white;
        }
        """
            % "rgba%s"
            % str(self.MainColor.getRgb()),
            "timeStyleSheet": """
        QSlider,QSlider:disabled,QSlider:focus{  
                                  background: qcolor(0,0,0,0);   }
         QSlider::groove:horizontal {
            border: 1px solid #999999;
            background: qcolor(0,0,0,0);
         }
        QSlider::handle:horizontal {
            background:  %s;
            width: 3px;
         } 
        """
            % "rgba%s"
            % str(self.MainColor.getRgb()),
        }
        return Styles[name]